package top.techqi.usbd.desc

import top.techqi.core.kext.WORD_T
import top.techqi.core.kext.hByte_T
import top.techqi.core.kext.lByte_T

class DeviceDesc(
    val bcdUSB: Short,
    val bDeviceClass: Byte,
    val bDeviceSubClass: Byte,
    val bDeviceProtocol: Byte,
    val bMaxPacketSize0: Byte,
    val idVendor: Short,
    val idProduct: Short,
    val bcdDevice: Short,
    val iManufacturer: Byte,
    val iProduct: Byte,
    val iSerialNumber: Byte,
    val bNumConfigurations: Byte,

    val manufacturer: String?,
    val productName: String?,
    val serialNumber: String?,
) : AbstractDesc(LENGTH, TYPE) {
    constructor(
        bytes: ByteArray,
        manufacturer: String?,
        productName: String?,
        serialNumber: String?,
    ) : this(
        WORD_T(bytes[3], bytes[2]),
        bytes[4],
        bytes[5],
        bytes[6],
        bytes[7],
        WORD_T(bytes[9], bytes[8]),
        WORD_T(bytes[11], bytes[10]),
        WORD_T(bytes[13], bytes[12]),
        bytes[14],
        bytes[15],
        bytes[16],
        bytes[17],

        manufacturer,
        productName,
        serialNumber,
    ) {
        require(bytes[0] == LENGTH && bytes[1] == TYPE) {
            "Invalid length or type: ${bytes[0]}, ${bytes[1]}"
        }
    }

    override fun toString(): String {
        return """
        DeviceDesc(
            bcdUSB          = %1${'$'}s,
            bDeviceClass    = %2${'$'}s,
            bDeviceSubClass = %3${'$'}s,
            bDeviceProtocol = %4${'$'}s,
            bMaxPacketSize0 = %5${'$'}s,
            idVendor        = %6${'$'}s,
            idProduct       = %7${'$'}s,
            bcdDevice       = %8${'$'}s,
            iManufacturer   = %9${'$'}s,
            iProduct        = %10${'$'}s,
            iSerialNumber   = %11${'$'}s,
            bNumConfigurations= %12${'$'}s
        )
        """.trimIndent().format(
            "0x%1$04X(%2$01X.%3$02X)".format(bcdUSB, bcdUSB.hByte_T, bcdUSB.lByte_T),
            "0x%1$02X".format(bDeviceClass),
            "0x%1$02X".format(bDeviceSubClass),
            "0x%1$02X".format(bDeviceProtocol),
            bMaxPacketSize0,
            "0x%1$04X".format(idVendor),
            "0x%04X".format(idProduct),
            "0x%1$04X(%2$01X.%3$02X)".format(bcdDevice, bcdDevice.hByte_T, bcdDevice.lByte_T),
            "%1$-2d(%2\$s)".format(iManufacturer, manufacturer),
            "%1$-2d(%2\$s)".format(iProduct, productName),
            "%1$-2d(%2\$s)".format(iSerialNumber, serialNumber),
            bNumConfigurations
        )
    }

    companion object {
        const val TYPE: Byte = 0x01
        const val LENGTH: Byte = 18
    }
}
